package com.wltjack.common.exception;

import com.wltjack.common.exception.code.SysErrorEnums;
import com.wltjack.common.exception.exceptions.BaseException;
import com.wltjack.common.exception.exceptions.ParamsException;
import com.wltjack.common.exception.exceptions.SysException;
import com.wltjack.common.reponse.Res;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.*;

/**
 * @ClassName GlobalExceptionHandler
 * @Description 全局异常控制处理
 * @Author kangliang
 * @Date 2021/03/02 21:33
 * @Version 1.0
 */
@SpringBootConfiguration
@ControllerAdvice
@Slf4j
@NoArgsConstructor
public class GlobalExceptionHandler {

    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    @ResponseBody
    public Res handlerRequstParams(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        this.printRequest(request);
        log.error("[error] - MethodArgumentTypeMismatchException:" + e.getMessage(), e);
        return Res.failed(null, 503, "参数错误：" + e.getMessage());
    }

    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseBody
    public Res handlerRequstParams(MissingServletRequestParameterException e, HttpServletRequest request) {
        this.printRequest(request);
        log.error("[error] - MissingServletRequestParameterException:" + e.getMessage(), e);
        return Res.failed(null, 503, "参数错误：" + e.getMessage());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public Res<Object> handleConstraintViolationException(ConstraintViolationException e) {

        StringBuilder sb = new StringBuilder();
        e.getConstraintViolations().forEach(error -> {
            String fieldName = error.getPropertyPath().toString();
            String message = error.getMessageTemplate();
            sb.append(fieldName + "-" + message + "；");
        });
        String result = sb.toString();
        if (result.length() > 0) {
            result = result.substring(0, result.length() - 1);
        }
        return Res.failed(null, 500, result);
    }


    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public Res methodArgumentNotValidHandler(MethodArgumentNotValidException exception, HttpServletRequest request) throws Exception {
        this.printRequest(request);
        StringBuilder sb = new StringBuilder();
        exception.getBindingResult().getFieldErrors().forEach(error -> {
            String fieldName = error.getField();
            String message = error.getDefaultMessage();
            sb.append(fieldName + "-" + message + "；");
        });
        String result = sb.toString();
        if (result.length() > 0) {
            result = result.substring(0, result.length() - 1);
        }
        log.error("MethodArgumentNotValidHandler:" + exception.getMessage(), exception);
        return Res.failed(null, 500, result);
    }

    @ExceptionHandler({BindException.class})
    @ResponseBody
    public Res bindException(BindException exception, HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        exception.getFieldErrors().forEach(error -> {
            String fieldName = error.getField();
            String message = error.getDefaultMessage();
            sb.append(fieldName + "-" + message + "；");
        });
        String result = sb.toString();
        if (result.length() > 0) {
            result = result.substring(0, result.length() - 1);
        }
        log.error("BindException:" + exception.getMessage(), exception);
        return Res.failed(null, 500, result);
    }

    @ExceptionHandler({ServletException.class})
    @ResponseBody
    public Res servletException(ServletException e, HttpServletRequest request) {
        this.printRequest(request);
        log.error("[error] - MissingServletRequestParameterException:" + e.getMessage(), e);
        return Res.failed(null, 503, "请求错误：" + e.getMessage());
    }

    @ExceptionHandler({BaseException.class})
    @ResponseBody
    public Res baseException(HttpServletRequest request, BaseException e) {
        this.printRequest(request);
        log.error("BaseException: errorCode:" + e.getError().getCode() + "[" + e.getError().getMessage() + "]" + e.getData(), e);
        return Res.failed(null, e.getError().getCode(), e.getError().getMessage());
    }

    @ExceptionHandler({SysException.class})
    @ResponseBody
    public Res sysException(SysException e, HttpServletRequest request) {
        this.printRequest(request);
        log.error("[error] - SysException:" + e.getError().getMessage(), e);
        return Res.failed(null, e.getError().getCode(), e.getError().getMessage());
    }

    @ExceptionHandler({ParamsException.class})
    @ResponseBody
    public Res paramsException(ParamsException e, HttpServletRequest request) {
        this.printRequest(request);
        log.error("[error] - ParamsException:" + e.getError(), e);
        return Res.failed(null, e.getError().getCode(), e.getError().getMessage());
    }

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public Res handleGlobal(HttpServletRequest request, Exception e) {
        this.printRequest(request);
        log.error("Exception:" + e.getMessage(), e);
        if (e instanceof NullPointerException) {
            return Res.failed(null, SysErrorEnums.SERVICE_ERROR.getCode(), "java.lang.NullPointerException");
        }
        return Res.failed(null, SysErrorEnums.SERVICE_ERROR.getCode(), e.getMessage());
    }

    private Res bindParamValid(BindingResult result) {
        List<Object> invalidArguments = new ArrayList();
        Res response = new Res(406, null, null);
        if (result.hasErrors()) {
            Iterator var4 = result.getFieldErrors().iterator();
            if (var4.hasNext()) {
                FieldError error = (FieldError) var4.next();
                Map<String, String> map = new HashMap(20);
                map.put("filed", error.getField());
                map.put("errorMsg", error.getDefaultMessage());
                invalidArguments.add(map);
                response.setMsg(error.getDefaultMessage());
                return response;
            }
        }
        return response;
    }

    /**
     * 功能描述: 打印 HttpServletRequest
     *
     * @param request HttpServletRequest
     * @return: void
     * @Author: kangliang
     * @Date: 2021-03-02 21:37
     */
    public void printRequest(HttpServletRequest request) {
        StringBuffer buf = new StringBuffer("request err! url:");
        buf.append(request.getRequestURL().toString()).append("\nheader:\n");
        Enumeration headers = request.getHeaderNames();

        while (headers.hasMoreElements()) {
            String header = (String) headers.nextElement();
            buf.append("\t").append(header + "=" + request.getHeader(header) + "\n");
        }

        buf.append("params:\n");
        Enumeration params = request.getParameterNames();

        while (params.hasMoreElements()) {
            String param = (String) params.nextElement();
            buf.append("\t").append(param + "=" + request.getParameter(param) + "\n");
        }

        log.error(buf.toString());
    }


}
